#pragma once

#include <iostream>
#include <cstdint>
#include <string>
#include<vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <thread>
#include <functional>
#include <memory>
using namespace std;

#define default_backlog 5

// 设计模式：模版方法类
class my_socket // 抽象类
{
public:
    virtual void Creat_socket() = 0; // 纯虚函数,必须重写
    virtual void Bind(int port) = 0;
    virtual void Listen(int backlog) = 0;
    virtual my_socket *Accept(string &ip, uint16_t &port) = 0;
    virtual void Connect(string ip, uint16_t port) = 0;
    virtual int Get_sockfd() = 0;
    virtual void Close() = 0;

    virtual void Recv(string &ret, int len) = 0;
    virtual void Send(string s) = 0;

public:
    void tcpserver_socket(uint16_t port, int backlog = default_backlog)
    {
        Creat_socket();
        Bind(port);
        Listen(backlog);
        // 因为服务会返回的执行accept获取连接，所以选择分离
    }
    void tcpclient_socket(string ip, uint16_t port)
    {
        Creat_socket();
        Connect(ip, port);
    }
};

class tcp_socket : public my_socket // 继承并重写虚函数
{
public:
    tcp_socket()
    {
    }
    tcp_socket(int sockfd)
        : _sockfd(sockfd)
    {
    }
    virtual void Creat_socket()
    {
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd < 0)
        {
            cerr << "创建套接字失败" << endl;
            exit(-1);
        }
    }
    virtual void Bind(int port)
    {
        struct sockaddr_in local;
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;

        int n = bind(_sockfd, (sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            cerr << "绑定套接字失败" << endl;
            exit(-1);
        }
    }
    virtual void Listen(int backlog)
    {
        int n = listen(_sockfd, backlog);
        if (n == -1)
        {
            cerr << "监听套接字失败" << endl;
            exit(-1);
        }
    }
    virtual my_socket *Accept(string &ip, uint16_t &port)
    {
        while (1)
        {
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int newsockfd = accept(_sockfd, (sockaddr *)&client, &len); // 监听套接字不关闭，可以用来接收多个客户端的连接
            if (newsockfd < 0)
            {
                cerr << "获取连接失败" << endl;
            }

            port = ntohs(client.sin_port);
            char buffer[64];
            inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer)); // 1.网络转本机 2.4字节ip转字符串ip
            ip = buffer;

            if (newsockfd < 0)
            {
                cerr << "接收套接字失败" << endl;
            }
            else
                cout << "接收套接字成功" << endl;

            return new tcp_socket(newsockfd);
        }
    }
    virtual void Connect(string ip, uint16_t port)
    {
        struct sockaddr_in server;
        server.sin_family = AF_INET;   // socket inet(ip) 协议家族,绑定网络通信的信息
        server.sin_port = htons(port); // 将主机端口号转成网络
        // server.sin_addr.s_addr = inet_addr(ip.c_str()); // 转成网络序列的四字节ip
        inet_pton(AF_INET, ip.c_str(), &server.sin_addr); // 转成网络序列的四字节ip

        int n = connect(_sockfd, (sockaddr *)&server, sizeof(server)); // 自动bind
        if (n != 0)
        {
            cerr << "连接失败" << endl;
            exit(-1);
        }
        else
            cout << "连接成功" << endl;
    }

    virtual int Get_sockfd()
    {
        return _sockfd;
    }

    virtual void Close()
    {
        if (_sockfd > 0)
            close(_sockfd);
    }

    virtual void Recv(string &ret, int len)
    {
        char stream_buffer[len];
        int n = recv(_sockfd, stream_buffer, len - 1, 0);

        if (n > 0)
        {
            stream_buffer[n] = 0;
            ret += stream_buffer; // ret在读取之前可能还有内容残留
        }
        else
        {
            exit(0);
        }
    }

    virtual void Send(string s)
    {
        send(_sockfd, s.c_str(), s.size(), 0);
    }

private:
    int _sockfd;
};
